home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / cdrtools-1.10 / libfile / apprentice.c next >
Encoding:
C/C++ Source or Header  |  2000-03-06  |  12.0 KB  |  601 lines

  1. /*
  2. **    find file types by using a modified "magic" file
  3. **
  4. **    based on file v3.22 by Ian F. Darwin (see below)
  5. **
  6. **    Modified for mkhybrid James Pearson 19/5/98
  7. */
  8.  
  9. /*
  10.  * apprentice - make one pass through /etc/magic, learning its secrets.
  11.  *
  12.  * Copyright (c) Ian F. Darwin, 1987.
  13.  * Written by Ian F. Darwin.
  14.  *
  15.  * This software is not subject to any license of the American Telephone
  16.  * and Telegraph Company or of the Regents of the University of California.
  17.  *
  18.  * Permission is granted to anyone to use this software for any purpose on
  19.  * any computer system, and to alter it and redistribute it freely, subject
  20.  * to the following restrictions:
  21.  *
  22.  * 1. The author is not responsible for the consequences of use of this
  23.  *    software, no matter how awful, even if they arise from flaws in it.
  24.  *
  25.  * 2. The origin of this software must not be misrepresented, either by
  26.  *    explicit claim or by omission.  Since few users ever read sources,
  27.  *    credits must appear in the documentation.
  28.  *
  29.  * 3. Altered versions must be plainly marked as such, and must not be
  30.  *    misrepresented as being the original software.  Since few users
  31.  *    ever read sources, credits must appear in the documentation.
  32.  *
  33.  * 4. This notice may not be removed or altered.
  34.  */
  35.  
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <ctype.h>
  40. #include <errno.h>
  41. #include "file.h"
  42.  
  43. #ifndef    lint
  44. static char *moduleid = 
  45.     "@(#)$Id: apprentice.c,v 1.25 1997/01/15 17:23:24 christos Exp $";
  46. #endif    /* lint */
  47.  
  48. #define    EATAB {while (isascii((unsigned char) *l) && \
  49.               isspace((unsigned char) *l))  ++l;}
  50. #define LOWCASE(l) (isupper((unsigned char) (l)) ? \
  51.             tolower((unsigned char) (l)) : (l))
  52.  
  53.  
  54. static int getvalue    __P((struct magic *, char **));
  55. static int hextoint    __P((int));
  56. static char *getstr    __P((char *, char *, int, int *));
  57. static int parse    __P((char *, int *, int));
  58. static void eatsize    __P((char **));
  59.  
  60. static int maxmagic = 0;
  61.  
  62. static int apprentice_1    __P((char *, int));
  63.  
  64. /*
  65.  * init_magic - read magic file and set up mapping
  66.  * based on the original apprentice()
  67.  */
  68. int
  69. init_magic(fn)
  70. char *fn;            /* list of magic files */
  71. {
  72.         maxmagic = MAXMAGIS;
  73.     magic = (struct magic *) calloc(sizeof(struct magic), maxmagic);
  74.     if (magic == NULL) 
  75.         return -1;
  76.  
  77.     return(apprentice_1(fn, 0));
  78. }
  79.  
  80. static int
  81. apprentice_1(fn, check)
  82. char *fn;            /* name of magic file */
  83. int check;            /* non-zero? checking-only run. */
  84. {
  85.     static const char hdr[] =
  86.         "cont\toffset\ttype\topcode\tmask\tvalue\tdesc";
  87.     FILE *f;
  88.     char line[BUFSIZ+1];
  89.     int errs = 0;
  90.  
  91.     f = fopen(fn, "r");
  92.     if (f==NULL) {
  93.         return -1;
  94.     }
  95.  
  96.     /* parse it */
  97.     if (check)    /* print silly verbose header for USG compat. */
  98.         (void) printf("%s\n", hdr);
  99.  
  100.     for (lineno = 1;fgets(line, BUFSIZ, f) != NULL; lineno++) {
  101.         if (line[0]=='#')    /* comment, do not parse */
  102.             continue;
  103.         if (strlen(line) <= (unsigned)1) /* null line, garbage, etc */
  104.             continue;
  105.         line[strlen(line)-1] = '\0'; /* delete newline */
  106.         if (parse(line, &nmagic, check) != 0)
  107.             errs = 1;
  108.     }
  109.  
  110.     (void) fclose(f);
  111.     return errs;
  112. }
  113.  
  114. /*
  115.  * extend the sign bit if the comparison is to be signed
  116.  * XXX is uint32 really a good idea XXX JS
  117.  */
  118. uint32
  119. signextend(m, v)
  120. struct magic *m;
  121. uint32 v;
  122. {
  123.     if (!(m->flag & UNSIGNED))
  124.         switch(m->type) {
  125.         /*
  126.          * Do not remove the casts below.  They are
  127.          * vital.  When later compared with the data,
  128.          * the sign extension must have happened.
  129.          */
  130.         case BYTE:
  131.             v = (char) v;
  132.             break;
  133.         case SHORT:
  134.         case BESHORT:
  135.         case LESHORT:
  136.             v = (short) v;
  137.             break;
  138.         case DATE:
  139.         case BEDATE:
  140.         case LEDATE:
  141.         case LONG:
  142.         case BELONG:
  143.         case LELONG:
  144.             v = (int32) v;
  145.             break;
  146.         case STRING:
  147.             break;
  148.         default:
  149.             return -1;
  150.         }
  151.     return v;
  152. }
  153.  
  154. /*
  155.  * parse one line from magic file, put into magic[index++] if valid
  156.  */
  157. static int
  158. parse(l, ndx, check)
  159. char *l;
  160. int *ndx, check;
  161. {
  162.     int i = 0, nd = *ndx;
  163.     struct magic *m;
  164.     char *t, *s;
  165.  
  166. #define ALLOC_INCR    20
  167.     if (nd+1 >= maxmagic){
  168.         maxmagic += ALLOC_INCR;
  169.         if ((magic = (struct magic *) realloc(magic, 
  170.                           sizeof(struct magic) * 
  171.                           maxmagic)) == NULL) {
  172.         (void) fprintf(stderr, "%s: Out of memory.\n", progname);
  173.         if (check)
  174.             return -1;
  175.         else
  176.             exit(1);
  177.         }
  178.         memset(&magic[*ndx], 0, sizeof(struct magic) * ALLOC_INCR);
  179.     }
  180.     m = &magic[*ndx];
  181.     m->flag = 0;
  182.     m->cont_level = 0;
  183.  
  184.     while (*l == '>') {
  185.         ++l;        /* step over */
  186.         m->cont_level++; 
  187.     }
  188.  
  189.     if (m->cont_level != 0 && *l == '(') {
  190.         ++l;        /* step over */
  191.         m->flag |= INDIR;
  192.     }
  193.     if (m->cont_level != 0 && *l == '&') {
  194.                 ++l;            /* step over */
  195.                 m->flag |= ADD;
  196.         }
  197.  
  198.     /* get offset, then skip over it */
  199.     m->offset = (int) strtoul(l,&t,0);
  200. /*
  201.         if (l == t)
  202.         magwarn("offset %s invalid", l);
  203. */
  204.         l = t;
  205.  
  206.     if (m->flag & INDIR) {
  207.         m->in.type = LONG;
  208.         m->in.offset = 0;
  209.         /*
  210.          * read [.lbs][+-]nnnnn)
  211.          */
  212.         if (*l == '.') {
  213.             l++;
  214.             switch (LOWCASE(*l)) {
  215.             case 'l':
  216.                 m->in.type = LONG;
  217.                 break;
  218.             case 'h':
  219.             case 's':
  220.                 m->in.type = SHORT;
  221.                 break;
  222.             case 'c':
  223.             case 'b':
  224.                 m->in.type = BYTE;
  225.                 break;
  226.             default:
  227.                 break;
  228.             }
  229.             l++;
  230.         }
  231.         s = l;
  232.         if (*l == '+' || *l == '-') l++;
  233.         if (isdigit((unsigned char)*l)) {
  234.             m->in.offset = strtoul(l, &t, 0);
  235.             if (*s == '-') m->in.offset = - m->in.offset;
  236.         }
  237.         else
  238.             t = l;
  239. /*
  240.         if (*t++ != ')') 
  241.             magwarn("missing ')' in indirect offset");
  242. */
  243.         l = t;
  244.     }
  245.  
  246.  
  247.     while (isascii((unsigned char)*l) && isdigit((unsigned char)*l))
  248.         ++l;
  249.     EATAB;
  250.  
  251. #define NBYTE        4
  252. #define NSHORT        5
  253. #define NLONG        4
  254. #define NSTRING     6
  255. #define NDATE        4
  256. #define NBESHORT    7
  257. #define NBELONG        6
  258. #define NBEDATE        6
  259. #define NLESHORT    7
  260. #define NLELONG        6
  261. #define NLEDATE        6
  262.  
  263.     if (*l == 'u') {
  264.         ++l;
  265.         m->flag |= UNSIGNED;
  266.     }
  267.  
  268.     /* get type, skip it */
  269.     if (strncmp(l, "byte", NBYTE)==0) {
  270.         m->type = BYTE;
  271.         l += NBYTE;
  272.     } else if (strncmp(l, "short", NSHORT)==0) {
  273.         m->type = SHORT;
  274.         l += NSHORT;
  275.     } else if (strncmp(l, "long", NLONG)==0) {
  276.         m->type = LONG;
  277.         l += NLONG;
  278.     } else if (strncmp(l, "string", NSTRING)==0) {
  279.         m->type = STRING;
  280.         l += NSTRING;
  281.     } else if (strncmp(l, "date", NDATE)==0) {
  282.         m->type = DATE;
  283.         l += NDATE;
  284.     } else if (strncmp(l, "beshort", NBESHORT)==0) {
  285.         m->type = BESHORT;
  286.         l += NBESHORT;
  287.     } else if (strncmp(l, "belong", NBELONG)==0) {
  288.         m->type = BELONG;
  289.         l += NBELONG;
  290.     } else if (strncmp(l, "bedate", NBEDATE)==0) {
  291.         m->type = BEDATE;
  292.         l += NBEDATE;
  293.     } else if (strncmp(l, "leshort", NLESHORT)==0) {
  294.         m->type = LESHORT;
  295.         l += NLESHORT;
  296.     } else if (strncmp(l, "lelong", NLELONG)==0) {
  297.         m->type = LELONG;
  298.         l += NLELONG;
  299.     } else if (strncmp(l, "ledate", NLEDATE)==0) {
  300.         m->type = LEDATE;
  301.         l += NLEDATE;
  302.     } else {
  303.         return -1;
  304.     }
  305.     /* New-style anding: "0 byte&0x80 =0x80 dynamically linked" */
  306.     if (*l == '&') {
  307.         ++l;
  308.         m->mask = signextend(m, (uint32)strtoul(l, &l, 0)); /* XXX JS uint32 cat may be wrong */
  309.         eatsize(&l);
  310.     } else
  311.         m->mask = ~0L;
  312.     EATAB;
  313.   
  314.     switch (*l) {
  315.     case '>':
  316.     case '<':
  317.     /* Old-style anding: "0 byte &0x80 dynamically linked" */
  318.     case '&':
  319.     case '^':
  320.     case '=':
  321.           m->reln = *l;
  322.           ++l;
  323.         break;
  324.     case '!':
  325.         if (m->type != STRING) {
  326.             m->reln = *l;
  327.             ++l;
  328.             break;
  329.         }
  330.         /* FALL THROUGH */
  331.     default:
  332.         if (*l == 'x' && isascii((unsigned char)l[1]) && 
  333.             isspace((unsigned char)l[1])) {
  334.             m->reln = *l;
  335.             ++l;
  336.             goto GetDesc;    /* Bill The Cat */
  337.         }
  338.           m->reln = '=';
  339.         break;
  340.     }
  341.       EATAB;
  342.   
  343.     if (getvalue(m, &l))
  344.         return -1;
  345.     /*
  346.      * TODO finish this macro and start using it!
  347.      * #define offsetcheck {if (offset > HOWMANY-1) 
  348.      *    magwarn("offset too big"); }
  349.      */
  350.  
  351.     /*
  352.      * now get last part - the description
  353.      */
  354. GetDesc:
  355.     EATAB;
  356.     if (l[0] == '\b') {
  357.         ++l;
  358.         m->nospflag = 1;
  359.     } else if ((l[0] == '\\') && (l[1] == 'b')) {
  360.         ++l;
  361.         ++l;
  362.         m->nospflag = 1;
  363.     } else
  364.         m->nospflag = 0;
  365.     while ((m->desc[i++] = *l++) != '\0' && i<MAXDESC)
  366.         /* NULLBODY */;
  367.  
  368.     ++(*ndx);        /* make room for next */
  369.     return 0;
  370. }
  371.  
  372. /* 
  373.  * Read a numeric value from a pointer, into the value union of a magic 
  374.  * pointer, according to the magic type.  Update the string pointer to point 
  375.  * just after the number read.  Return 0 for success, non-zero for failure.
  376.  */
  377. static int
  378. getvalue(m, p)
  379. struct magic *m;
  380. char **p;
  381. {
  382.     int slen;
  383.  
  384.     if (m->type == STRING) {
  385.         *p = getstr(*p, m->value.s, sizeof(m->value.s), &slen);
  386.         m->vallen = slen;
  387.     } else
  388.         if (m->reln != 'x') {
  389.             m->value.l = signextend(m, (uint32)strtoul(*p, p, 0)); /* XXX JS uint32 cat may be wrong */
  390.             eatsize(p);
  391.         }
  392.     return 0;
  393. }
  394.  
  395. /*
  396.  * Convert a string containing C character escapes.  Stop at an unescaped
  397.  * space or tab.
  398.  * Copy the converted version to "p", returning its length in *slen.
  399.  * Return updated scan pointer as function result.
  400.  */
  401. static char *
  402. getstr(s, p, plen, slen)
  403. register char    *s;
  404. register char    *p;
  405. int    plen, *slen;
  406. {
  407.     char    *origs = s, *origp = p;
  408.     char    *pmax = p + plen - 1;
  409.     register int    c;
  410.     register int    val;
  411.  
  412.     while ((c = *s++) != '\0') {
  413.         if (isspace((unsigned char) c))
  414.             break;
  415.         if (p >= pmax) {
  416.             fprintf(stderr, "String too long: %s\n", origs);
  417.             break;
  418.         }
  419.         if(c == '\\') {
  420.             switch(c = *s++) {
  421.  
  422.             case '\0':
  423.                 goto out;
  424.  
  425.             default:
  426.                 *p++ = (char) c;
  427.                 break;
  428.  
  429.             case 'n':
  430.                 *p++ = '\n';
  431.                 break;
  432.  
  433.             case 'r':
  434.                 *p++ = '\r';
  435.                 break;
  436.  
  437.             case 'b':
  438.                 *p++ = '\b';
  439.                 break;
  440.  
  441.             case 't':
  442.                 *p++ = '\t';
  443.                 break;
  444.  
  445.             case 'f':
  446.                 *p++ = '\f';
  447.                 break;
  448.  
  449.             case 'v':
  450.                 *p++ = '\v';
  451.                 break;
  452.  
  453.             /* \ and up to 3 octal digits */
  454.             case '0':
  455.             case '1':
  456.             case '2':
  457.             case '3':
  458.             case '4':
  459.             case '5':
  460.             case '6':
  461.             case '7':
  462.                 val = c - '0';
  463.                 c = *s++;  /* try for 2 */
  464.                 if(c >= '0' && c <= '7') {
  465.                     val = (val<<3) | (c - '0');
  466.                     c = *s++;  /* try for 3 */
  467.                     if(c >= '0' && c <= '7')
  468.                         val = (val<<3) | (c-'0');
  469.                     else
  470.                         --s;
  471.                 }
  472.                 else
  473.                     --s;
  474.                 *p++ = (char)val;
  475.                 break;
  476.  
  477.             /* \x and up to 2 hex digits */
  478.             case 'x':
  479.                 val = 'x';    /* Default if no digits */
  480.                 c = hextoint(*s++);    /* Get next char */
  481.                 if (c >= 0) {
  482.                     val = c;
  483.                     c = hextoint(*s++);
  484.                     if (c >= 0)
  485.                         val = (val << 4) + c;
  486.                     else
  487.                         --s;
  488.                 } else
  489.                     --s;
  490.                 *p++ = (char)val;
  491.                 break;
  492.             }
  493.         } else
  494.             *p++ = (char)c;
  495.     }
  496. out:
  497.     *p = '\0';
  498.     *slen = p - origp;
  499.     return s;
  500. }
  501.  
  502.  
  503. /* Single hex char to int; -1 if not a hex char. */
  504. static int
  505. hextoint(c)
  506. int c;
  507. {
  508.     if (!isascii((unsigned char) c))    return -1;
  509.     if (isdigit((unsigned char) c))        return c - '0';
  510.     if ((c>='a')&&(c<='f'))    return c + 10 - 'a';
  511.     if ((c>='A')&&(c<='F'))    return c + 10 - 'A';
  512.                 return -1;
  513. }
  514.  
  515.  
  516. /*
  517.  * Print a string containing C character escapes.
  518.  */
  519. void
  520. showstr(fp, s, len)
  521. FILE *fp;
  522. const char *s;
  523. int len;
  524. {
  525.     register char    c;
  526.  
  527.     for (;;) {
  528.         c = *s++;
  529.         if (len == -1) {
  530.             if (c == '\0')
  531.                 break;
  532.         }
  533.         else  {
  534.             if (len-- == 0)
  535.                 break;
  536.         }
  537.         if(c >= 040 && c <= 0176)    /* TODO isprint && !iscntrl */
  538.             (void) fputc(c, fp);
  539.         else {
  540.             (void) fputc('\\', fp);
  541.             switch (c) {
  542.             
  543.             case '\n':
  544.                 (void) fputc('n', fp);
  545.                 break;
  546.  
  547.             case '\r':
  548.                 (void) fputc('r', fp);
  549.                 break;
  550.  
  551.             case '\b':
  552.                 (void) fputc('b', fp);
  553.                 break;
  554.  
  555.             case '\t':
  556.                 (void) fputc('t', fp);
  557.                 break;
  558.  
  559.             case '\f':
  560.                 (void) fputc('f', fp);
  561.                 break;
  562.  
  563.             case '\v':
  564.                 (void) fputc('v', fp);
  565.                 break;
  566.  
  567.             default:
  568.                 (void) fprintf(fp, "%.3o", c & 0377);
  569.                 break;
  570.             }
  571.         }
  572.     }
  573. }
  574.  
  575. /*
  576.  * eatsize(): Eat the size spec from a number [eg. 10UL]
  577.  */
  578. static void
  579. eatsize(p)
  580. char **p;
  581. {
  582.     char *l = *p;
  583.  
  584.     if (LOWCASE(*l) == 'u') 
  585.         l++;
  586.  
  587.     switch (LOWCASE(*l)) {
  588.     case 'l':    /* long */
  589.     case 's':    /* short */
  590.     case 'h':    /* short */
  591.     case 'b':    /* char/byte */
  592.     case 'c':    /* char/byte */
  593.         l++;
  594.         /*FALLTHROUGH*/
  595.     default:
  596.         break;
  597.     }
  598.  
  599.     *p = l;
  600. }
  601.